#include "main.h"

environment::environment()
{
    Object obj;

    obj = Symbol(new symbol("false", false));
    bind(obj, obj);
    obj = Symbol(new symbol("true", false));
    bind(obj, obj);
    obj = Symbol(new symbol("eof", false));
    bind(obj, obj);
    obj = Symbol(new symbol("lambda", false));
    bind(obj, obj);
    input = Symbol(new symbol("stdin"));
    output = Symbol(new symbol("stdout"));
    bind(input, Port(new port(stdin)));
    bind(output, Port(new port(stdout, false)));
    bind(Symbol(new symbol("quote")), Funcs(new funcs("quote")));
    bind(Symbol(new symbol("eval")), Funcs(new funcs("eval")));
    bind(Symbol(new symbol("define")), Funcs(new funcs("define")));
    bind(Symbol(new symbol("if")), Funcs(new funcs("if")));
    bind(Symbol(new symbol("+")), Funcs(new funcs("+")));
    bind(Symbol(new symbol("-")), Funcs(new funcs("-")));
    bind(Symbol(new symbol("*")), Funcs(new funcs("*")));
    bind(Symbol(new symbol("/")), Funcs(new funcs("/")));
    bind(Symbol(new symbol("%")), Funcs(new funcs("%")));
    bind(Symbol(new symbol("exp")), Funcs(new funcs("exp")));
    bind(Symbol(new symbol("sqrt")), Funcs(new funcs("sqrt")));
    bind(Symbol(new symbol("==")), Funcs(new funcs("==")));
    bind(Symbol(new symbol("!=")), Funcs(new funcs("!=")));
    bind(Symbol(new symbol("<")), Funcs(new funcs("<")));
    bind(Symbol(new symbol(">")), Funcs(new funcs(">")));
    bind(Symbol(new symbol("<=")), Funcs(new funcs("<=")));
    bind(Symbol(new symbol(">=")), Funcs(new funcs(">=")));
    bind(Symbol(new symbol("apply")), Funcs(new funcs("apply")));
    bind(Symbol(new symbol("and")), Funcs(new funcs("and")));
    bind(Symbol(new symbol("or")), Funcs(new funcs("or")));
}

void environment::bind(Object a, Object b) {
    for (std::list<std::pair<Object, Object> >::iterator it = env.begin(); it != env.end(); ++it)
	if (it->first == a) {
	    if (it->first->ischange())
		it->second = b;
	    return;
	}
    env.push_front(std::pair<Object, Object>(a, b));
}

Object environment::get_value(std::string s) {
    for (std::list<std::pair<Object, Object> >::iterator it = env.begin(); it != env.end(); ++it)
	if (it->first->to_string() == s)
	    return it->second;
    throw Error(new error(error::notport));
}

Object environment::get_value_read(std::string s) {
    for (std::list<std::pair<Object, Object> >::iterator it = env.begin(); it != env.end(); ++it)
	if (it->first->to_string() == s)
	    return it->first;
    throw Error(new error(error::notport));
}

void environment::bind_arg(Environment env, Object arg) {
    Object obj = arg;
    Cons narg(new cons(env)), nap = narg;
    Symbol sym(new symbol("arg"));

    bind(get_value_read("false"), get_value("false"));
    narg->set_car(obj->get_car()->eval(env));
    for (obj = obj->get_cdr(); obj->to_string() != "false"; obj = obj->get_cdr()) {
	nap->set_cdr(Cons(new cons(env)));
	nap = boost::dynamic_pointer_cast<cons>(nap->get_cdr());
	nap->set_car(obj->get_car()->eval(env));
    }
    bind(sym, narg);
}

void environment::auto_remove() {
    for (; env.front().first->to_string() == "false"; env.pop_front());
    env.pop_front();
}
